#ifndef WINDOW_OPCODE_H
#define WINDOW_OPCODE_H

#include "gkt_types.h"

#ifdef __cplusplus
extern "C" {
#endif

#define WINDOW_OPCODE_CURRENT	0xFFFF

/* opcode form
 * 1. [0x000 ~ 0x6FF] normal
 *    1.1 high byte : major
 *    1.2 low byte  : minor
 * 2. [0x700 ~ ] compatible
 */

#define WINDOW_OPCODE_MINOR_SHIFT	0
#define WINDOW_OPCODE_MINOR_BITS	8
#define WINDOW_OPCODE_MINOR_MASK	\
	((1U << WINDOW_OPCODE_MINOR_BITS) - 1)

#define WINDOW_OPCODE_MAJOR_SHIFT	\
	(WINDOW_OPCODE_MINOR_SHIFT + WINDOW_OPCODE_MINOR_BITS)
#define WINDOW_OPCODE_MAJOR_BITS	8
#define WINDOW_OPCODE_MAJOR_MASK	\
	(((1U << WINDOW_OPCODE_MAJOR_BITS) - 1) << WINDOW_OPCODE_MAJOR_SHIFT)


#define WINDOW_OPCODE_MAX_BITS	\
	(WINDOW_OPCODE_MINOR_BITS + WINDOW_OPCODE_MAJOR_BITS)

#define WINDOW_OPCODE_MAJOR(opcode)	\
	(((opcode) & WINDOW_OPCODE_MAJOR_MASK) >> WINDOW_OPCODE_MAJOR_SHIFT)
#define WINDOW_OPCODE_MINOR(opcode)	\
	((opcode) & WINDOW_OPCODE_MINOR_MASK)

/* major */
enum {
	WINDOW_OPCODE_MAJOR_COMMON = 0,
	WINDOW_OPCODE_MAJOR_USER_ADD,
	WINDOW_OPCODE_MAJOR_USER_DELETE,
	WINDOW_OPCODE_MAJOR_SET,
	WINDOW_OPCODE_MAJOR_SWITCH,
	WINDOW_OPCODE_MAJOR_MAX,
};


/* common - sub_type */
enum {
	WINDOW_OPCODE_COMMON_SYSTEM_INFO = 0,
	WINDOW_OPCODE_COMMON_CONFIRM,
	WINDOW_OPCODE_COMMON_CANCEL,
	WINDOW_OPCODE_COMMON_EXIT,
	WINDOW_OPCODE_COMMON_STANDBY,

	WINDOW_OPCODE_COMMON_FACTORY_RESET = 0xF0,
	WINDOW_OPCODE_COMMON_FACTORY_TEST,
	WINDOW_OPCODE_COMMON_AGING_TEST,
	WINDOW_OPCODE_COMMON_SUB_TYPE_MAX
};
#define WINDOW_OPCODE_COMMON(_sub_type_name)	\
	((WINDOW_OPCODE_MAJOR_COMMON << WINDOW_OPCODE_MAJOR_SHIFT) | \
		WINDOW_OPCODE_COMMON_##_sub_type_name)

/* user_add */
#define WINDOW_OPCODE_USER_ADD_TYPE_SHIFT	0
#define WINDOW_OPCODE_USER_ADD_TYPE_BITS	4
#define WINDOW_OPCODE_USER_ADD_TYPE_MASK	\
	((1U << WINDOW_OPCODE_USER_ADD_TYPE_BITS) - 1)

#define WINDOW_OPCODE_USER_ADD_AUTHORITY_SHIFT	\
	(WINDOW_OPCODE_USER_ADD_TYPE_SHIFT + WINDOW_OPCODE_USER_ADD_TYPE_BITS)
#define WINDOW_OPCODE_USER_ADD_AUTHORITY_BITS	\
	(WINDOW_OPCODE_MINOR_BITS - WINDOW_OPCODE_USER_ADD_TYPE_BITS)
#define WINDOW_OPCODE_USER_ADD_AUTHORITY_MASK	\
	((1U << WINDOW_OPCODE_USER_ADD_AUTHORITY_BITS) - 1)

#define WINDOW_OPCODE_USER_ADD(_authority_name, _type_name)	\
	((WINDOW_OPCODE_MAJOR_USER_ADD << WINDOW_OPCODE_MAJOR_SHIFT) | \
		(GKT_USER_AUTH_##_authority_name << WINDOW_OPCODE_USER_ADD_AUTHORITY_SHIFT) | \
		GKT_USER_TYPE_##_type_name)


/* user_delete */
#define WINDOW_OPCODE_USER_DELETE_TYPE_SHIFT	0
#define WINDOW_OPCODE_USER_DELETE_TYPE_BITS	4
#define WINDOW_OPCODE_USER_DELETE_AUTHORITY_SHIFT	\
	(WINDOW_OPCODE_USER_DELETE_TYPE_SHIFT + WINDOW_OPCODE_USER_DELETE_TYPE_BITS)
#define WINDOW_OPCODE_USER_DELETE_AUTHORITY_BITS	\
	(WINDOW_OPCODE_MINOR_BITS - WINDOW_OPCODE_USER_DELETE_TYPE_BITS)
#define WINDOW_OPCODE_USER_DELETE(_authority_name, _type_name)	\
	((WINDOW_OPCODE_MAJOR_USER_DELETE << WINDOW_OPCODE_MAJOR_SHIFT) | \
		(GKT_USER_AUTH_##_authority_name << WINDOW_OPCODE_USER_DELETE_AUTHORITY_SHIFT) | \
		GKT_USER_TYPE_##_type_name)


/* setting */
enum {
	/* sub_type */
	WINDOW_OPCODE_SET_SYSTEM_TIME = 0,
	WINDOW_OPCODE_SET_AUTO_LOCK_TIME,
	WINDOW_OPCODE_SET_GUEST_ACCESS_TIME,
	WINDOW_OPCODE_SET_MAX
};
#define WINDOW_OPCODE_SET(_sub_type_name)	\
	((WINDOW_OPCODE_MAJOR_SET << WINDOW_OPCODE_MAJOR_SHIFT) | \
		WINDOW_OPCODE_SET_##_sub_type_name)


/* switch */
#define WINDOW_OPCODE_SWITCH_ACTION_SHIFT	0
#define WINDOW_OPCODE_SWITCH_ACTION_BITS	2
#define WINDOW_OPCODE_SWITCH_ACTION_MASK	\
	((1U << WINDOW_OPCODE_SWITCH_ACTION_BITS) - 1)

#define WINDOW_OPCODE_SWITCH_SUB_TYPE_SHIFT	\
	(WINDOW_OPCODE_SWITCH_ACTION_SHIFT + WINDOW_OPCODE_SWITCH_ACTION_BITS)
#define WINDOW_OPCODE_SWITCH_SUB_TYPE_BITS	\
	(WINDOW_OPCODE_MINOR_BITS - WINDOW_OPCODE_SWITCH_SUB_TYPE_SHIFT)
#define WINDOW_OPCODE_SWITCH_SUB_TYPE_MASK	\
	((1U << WINDOW_OPCODE_SWITCH_SUB_TYPE_BITS) - 1)

enum {
	WINDOW_OPCODE_SWITCH_DUAL_VERIFY_UNLOCK = 0,
	WINDOW_OPCODE_SWITCH_DOOR_TAMPER_ALARM,
	WINDOW_OPCODE_SWITCH_SUB_TYPE_MAX
};
enum {
	WINDOW_OPCODE_SWITCH_CLOSE = 0,
	WINDOW_OPCODE_SWITCH_OPEN,
	WINDOW_OPCODE_SWITCH_ACTION_MAX
};
#define WINDOW_OPCODE_SWITCH(_sub_type_name, _action_name)	\
	((WINDOW_OPCODE_MAJOR_SWITCH << WINDOW_OPCODE_MAJOR_SHIFT) | \
		(WINDOW_OPCODE_SWITCH_##_sub_type_name << WINDOW_OPCODE_SWITCH_SUB_TYPE_SHIFT) | \
		WINDOW_OPCODE_SWITCH_##_action_name)

/* compatible opcode */
#define WINDOW_OPCODE_COMPATIBLE_NETWORK_SETTING 666
#define WINDOW_OPCODE_COMPATIBLE_MOTOR_SETTING	888
#define WINDOW_OPCODE_COMPATIBLE_MOTOR_ROTATE_DIRECTION	8880	// TODO:
#define WINDOW_OPCODE_COMPATIBLE_MOTOR_ROTATE_TIME	8881	// TODO:
#define WINDOW_OPCODE_COMPATIBLE_SYSTEM_INFO						1900
#define WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_1901				1901
#define WINDOW_OPCODE_COMPATIBLE_AGING_TEST							1902
#define WINDOW_OPCODE_COMPATIBLE_KEYPAD_PARAMETER_STANDARD 			1903
#define WINDOW_OPCODE_COMPATIBLE_KEYPAD_PARAMETER_SENSITIVE 		1904
#define WINDOW_OPCODE_COMPATIBLE_RFID_STANDBY_SOFT_POWEROFF 		1905
#define WINDOW_OPCODE_COMPATIBLE_RFID_STANDBY_LPCD 					1906
#define WINDOW_OPCODE_COMPATIBLE_FAST_STANDBY						1907
#define WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_1919 				1919
#define WINDOW_OPCODE_COMPATIBLE_FACTORY_INSPECT_3791				3791
#define WINDOW_OPCODE_COMPATIBLE_KEYPAD_OPEN_PARAMETER_TEST_PRINT	3792
#define WINDOW_OPCODE_COMPATIBLE_KEYPAD_OPEN_REAL_TRIM_PRINT		3793
#define WINDOW_OPCODE_COMPATIBLE_MOTOR_ROTATE_DIRECTION_FORWARD		3794
#define WINDOW_OPCODE_COMPATIBLE_MOTOR_ROTATE_DIRECTION_REVERSE		3795

/* opcode state */
enum {
	WINDOW_OPCODE_ST_IDLE = 0,
	WINDOW_OPCODE_ST_LOGGING,
	WINDOW_OPCODE_ST_HANDLING,
	WINDOW_OPCODE_ST_MAX
};

#define WINDOW_OPCODE_F_UNINITIALIZED	(1U << 0)
#define WINDOW_OPCODE_F_INITIALIZED	(1U << 1)
#define WINDOW_OPCODE_F_NEED_LOGIN	(1U << 2)
#define WINDOW_OPCODE_F_FROM_START	(1U << 3)
#define WINDOW_OPCODE_F_UNLIMITED	(1U << 4)

typedef void (*window_opcode_action_fn)(uint32_t minor, const void *data);
typedef uint32_t (*window_opcode_flags_fn)(uint32_t minor);

typedef struct _window_opcode_attr {
	window_opcode_action_fn	action_fn;
	window_opcode_flags_fn	flags_fn;
} window_opcode_attr_s;

#ifdef __cplusplus
}
#endif

#endif

